package com.loe.ktui.custom

import android.content.Context
import android.content.res.TypedArray
import android.graphics.*
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import androidx.core.content.res.getBooleanOrThrow
import androidx.core.content.res.getColorOrThrow
import androidx.core.content.res.getFloatOrThrow
import com.loe.ktui.R
import com.loe.ktui.UiGroup
import com.loe.ktui.UiView
import com.loe.ktui.util.KtColor

open class UiSwitch(id: String? = null) : UiView(id)
{
    var rate: Double? = null
    var unEnableColor: Int? = null
    var mainColor: Int? = null
    var baseColor: Int? = null
    var isChecked: Boolean? = null
    var isEnable: Boolean? = null

    var onChecked: (KtSwitch.(isChecked: Boolean) -> Unit)? = null
    fun onChecked(onChecked: KtSwitch.(isChecked: Boolean) -> Unit)
    {
        this.onChecked = onChecked
    }

    open fun initUI(context: Context, view: KtSwitch)
    {
        super.initUI(context, view)

        rate?.let { view.rate = it }
        unEnableColor?.let { view.unEnableColor = it }
        mainColor?.let { view.mainColor = it }
        baseColor?.let { view.baseColor = it }
        isChecked?.let { view.isChecked = it }
        isEnable?.let { view.isEnable = it }
        onChecked?.let { on -> view.setOnChecked { view.on(it) } }
    }

    /** 创建view */
    override fun createView(context: Context, parent: ViewGroup?): KtSwitch
    {
        return KtSwitch(context).also()
        {
            initUI(context, it)
            addToParent(parent, it)
        }
    }
}

fun Any.ui_Switch(id: String? = null, block: (UiSwitch.() -> Unit)? = null): UiSwitch
{
    val ui = UiSwitch(id)
    block?.let { ui.it() }
    if (this is UiGroup) addChild(ui)
    return ui
}

open class KtSwitch : View
{
    constructor(context: Context) : super(context)
    {
        initXML()
    }

    constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
    {
        initXML(context.obtainStyledAttributes(attrs, R.styleable.KtSwitch))
    }

    constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
    {
        initXML(context.obtainStyledAttributes(attrs, R.styleable.KtSwitch, defStyleAttr, 0))
    }

    private fun initXML(typedArray: TypedArray? = null)
    {
        setLayerType(LAYER_TYPE_SOFTWARE, null)
        typedArray?.let()
        {
            if (it.hasValue(R.styleable.KtSwitch_kt_rate))
            {
                rate = it.getFloatOrThrow(R.styleable.KtSwitch_kt_rate).toDouble()
            }
            if (it.hasValue(R.styleable.KtSwitch_kt_unEnableColor))
            {
                unEnableColor = it.getColorOrThrow(R.styleable.KtSwitch_kt_unEnableColor)
            }
            if (it.hasValue(R.styleable.KtSwitch_kt_mainColor))
            {
                mainColor = it.getColorOrThrow(R.styleable.KtSwitch_kt_mainColor)
            }
            if (it.hasValue(R.styleable.KtSwitch_kt_baseColor))
            {
                baseColor = it.getColorOrThrow(R.styleable.KtSwitch_kt_baseColor)
            }
            if (it.hasValue(R.styleable.KtSwitch_kt_isChecked))
            {
                isChecked = it.getBooleanOrThrow(R.styleable.KtSwitch_kt_isChecked)
            }
            if (it.hasValue(R.styleable.KtSwitch_kt_isEnable))
            {
                isEnable = it.getBooleanOrThrow(R.styleable.KtSwitch_kt_isEnable)
            }

            it.recycle()
        }
    }

    /********************************************************************************************/

    internal var rate = 0.53
    internal var unEnableColor: Int = KtColor.grayLight
    internal var mainColor: Int = KtColor.green
    internal var baseColor: Int = KtColor.white
    internal var onChecked: ((isChecked: Boolean) -> Unit)? = null
    var isChecked: Boolean = false
        internal set
    var isEnable: Boolean = true
        internal set

    private var w = 0
    private var h = 0
    private val mPaint = Paint()
    private var mAnimate = 0f
    private var r = 0f
    private var off = 0f
    private var offX = 0f
    private var offY = 0f
    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int)
    {
        w = MeasureSpec.getSize(widthMeasureSpec) - paddingLeft - paddingRight
        h = MeasureSpec.getSize(heightMeasureSpec) - paddingTop - paddingBottom
        if (w <= 0 || MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.EXACTLY)
        {
            w = (h / rate).toInt()
        }
        if (h <= 0 || MeasureSpec.getMode(heightMeasureSpec) != MeasureSpec.EXACTLY)
        {
            h = (rate * w).toInt()
        }
        r = h / 2f
        off = w * 0.05f
        offX = off + paddingLeft
        offY = off + paddingTop
        setMeasuredDimension(paddingLeft + (w + off * 2).toInt() + paddingRight, paddingTop + (h + off * 2.4).toInt() + paddingBottom)
    }

    override fun onDraw(canvas: Canvas)
    {
        super.onDraw(canvas)
        mPaint.style = Paint.Style.FILL
        mPaint.isAntiAlias = true

        // 动画标示 ，重绘10次，借鉴被人的动画
        mAnimate = if (mAnimate - 0.1f > 0) mAnimate - 0.15f else 0f
        val isAnimate = (if (!isChecked) 1 - mAnimate else mAnimate) > 0
        //平移距离
        val translate = (w - h) * (if (!isChecked) mAnimate else 1 - mAnimate) - 1f

        //绘制主色圆角矩形
        mPaint.color = if (isEnable) mainColor else unEnableColor
        mPaint.setShadowLayer(off + 2, 0f, off * 0.2f, 0x22000000)
        canvas.drawRoundRect(RectF(offX, offY, offX + w, offY + h), r, r, mPaint)

        //绘制收缩白色圆角矩形
        mPaint.color = baseColor
        mPaint.setShadowLayer(0f, 0f, 0f, 0)
        canvas.drawRoundRect(RectF(offX + translate, offY - 0.5f, offX + w + 1f, offY + h + 0.5f), r, r, mPaint)
        canvas.saveLayer(0f, 0f, getWidth().toFloat(), getHeight().toFloat(), null, Canvas.ALL_SAVE_FLAG)
        mPaint.color = baseColor
        mPaint.setShadowLayer(0f, 0f, 0f, 0)
        canvas.drawRoundRect(RectF(offX + translate, offY - 0.5f, offX + w + 1f, offY + h + 0.5f), r, r, mPaint)
        mPaint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN)

        // 绘制白色圆形
        mPaint.color = baseColor
        mPaint.setShadowLayer(off + 2, 0f, off * 0.2f + 1, 0x22000000)
        canvas.drawCircle(offX + r + translate, offY + r, r, mPaint)
        mPaint.xfermode = null
        canvas.restore()
        if (isAnimate)
        {
            mPaint.reset()
            invalidate()
        }
    }

    fun setMainColor(color: Int)
    {
        mainColor = color
    }

    fun setBaseColor(color: Int)
    {
        baseColor = color
    }

    private var isDown = false
    override fun onTouchEvent(event: MotionEvent): Boolean
    {
        if (isEnable) when (event.action)
        {
            MotionEvent.ACTION_DOWN ->
            {
                isDown = true
                return true
            }
            MotionEvent.ACTION_MOVE ->
            {
                isDown = inRangeOfView(event)
                return true
            }
            MotionEvent.ACTION_UP ->
            {
                if (isDown)
                {
                    setChecked(!isChecked)
                }
                isDown = false
            }
        }
        return super.onTouchEvent(event)
    }

    private fun inRangeOfView(ev: MotionEvent): Boolean
    {
        val location = IntArray(2)
        getLocationOnScreen(location)
        val x = location[0]
        val y = location[1]
        return !(ev.rawX < x || ev.rawX > x + width || ev.rawY < y || ev.rawY > y + height)
    }

    fun setCheckedNoListener(checked: Boolean)
    {
        if (isChecked != checked)
        {
            mAnimate = 1f
            isChecked = checked
            invalidate()
        }
    }

    fun setCheckedNoAnimate(checked: Boolean)
    {
        if (isChecked != checked)
        {
            isChecked = checked
            onChecked?.invoke(isChecked)
            invalidate()
        }
    }

    fun setChecked(checked: Boolean)
    {
        if (isChecked != checked)
        {
            mAnimate = 1f
            isChecked = checked
            onChecked?.invoke(isChecked)
            invalidate()
        }
    }

    fun setEnable(isEnable: Boolean)
    {
        this.isEnable = isEnable
        invalidate()
    }

    fun setOnChecked(value: Boolean?, onChecked: (isChecked: Boolean) -> Unit)
    {
        if(value != null)
        {
            setCheckedNoListener(value)
        }
        this.onChecked = onChecked
    }

    fun setOnChecked(onChecked: (isChecked: Boolean) -> Unit)
    {
        this.onChecked = onChecked
    }
}